//
//  Arch.h
//  Wood
//
//  Created by Wayne on 9/10/14.
//  Copyright (c) 2014 Wayne. All rights reserved.
//

#ifndef Wood_Arch_h
#define Wood_Arch_h

typedef enum {
    NO = 0,
    YES = 1
} BOOL;

typedef struct StringTag {
    char *string;
} String;

typedef enum {
    WdBoolValue = 1,
    WdIntValue,
    WdDoubleValue,
    WdStringValue,
    WdNullValue
} ValueType;

typedef struct {
    ValueType type;
    union {
        BOOL boolValue;
        int intValue;
        double doubleValue;
        String *stringValue;
    } u;
} Value;

typedef enum {
    WdBoolExpression = 1,
    WdIntExpression,
    WdDoubleExpression,
    WdStringExpression,
    WdIdentifierExpression,
    WdAssignExpression,
    WdAddExpression,
    WdSubExpression,
    WdMulExpression,
    WdDivExpression,
    WdModExpression,
    WdEqExpression,
    WdNeExpression,
    WdGtExpression,
    WdGeExpression,
    WdLtExpression,
    WdLeExpression,
    WdLogicalAndExpression,
    WdLogicalOrExpression,
    WdMinusExpression,
    WdFunctionCallExpression
} ExpressionType;

#define isMathOperator(operator) ((operator) == WdAddExpression || (operator) == WdSubExpression || (operator) == WdMulExpression || (operator) == WdDivExpression || (operator) == WdModExpression)
#define isComparisonOperator(operator) ((operator) == WdEqExpression || (operator) == WdNeExpression || (operator) == WdGtExpression || (operator) == WdGeExpression || (operator) == WdLtExpression || (operator) == WdLeExpression)
#define isLogicalOperator(operator) ((operator) == WdLogicalAndExpression || (operator) == WdLogicalOrExpression)

typedef struct ExpressionTag Expression;

typedef struct ArgumentListTag {
    Expression *expression;
    struct ArgumentListTag *next;
} ArgumentList;

typedef struct {
    char *variable;
    Expression *operand;
} AssignExpression;

typedef struct {
    Expression *left;
    Expression *right;
} BinaryExpression;

typedef struct {
    char *identifier;
    ArgumentList *argument;
} FunctionCallExpression;

struct ExpressionTag {
    ExpressionType type;
    int lineNumber;
    union {
        BOOL boolValue;
        int intValue;
        double doubleValue;
        String *stringValue;
        char *identifier;
        AssignExpression *assignExpression;
        BinaryExpression *binaryExpression;
        Expression *minusExpression;
        FunctionCallExpression *functionCallExpression;
    } u;
};

typedef enum {
    WdExpressionStatement = 1,
    WdReturnStatement,
    WdFunctionDefinitionStatement
} StatementType;

typedef struct StatementTag Statement;

typedef struct StatementListTag {
    Statement *statement;
    struct StatementListTag *next;
} StatementList;

typedef struct {
    StatementList *statementList;
} Block;

typedef struct ParameterListTag {
    char *name;
    struct ParameterListTag *next;
} ParameterList;

typedef struct {
    Expression *returnExpression;
} ReturnStatement;

typedef struct {
    char *identifier;
    ParameterList *parameter;
    Block *block;
} FunctionDefinitionStatement;

struct StatementTag {
    StatementType type;
    int lineNumber;
    union {
        Expression *expressionStatement;
        ReturnStatement *returnStatement;
        FunctionDefinitionStatement *functionDefinitionStatement;
    } u;
};

typedef enum {
    WdWoodFunctionDefinition = 1,
    WdNativeFunctionDefinition
} FunctionDefinitionType;

typedef Value nativeFunctionProc(int argc, Value *args);

typedef struct FunctionDefinitionTag {
    FunctionDefinitionType type;
    char *name;
    union {
        struct {
            ParameterList *parameter;
            Block *block;
        } woodFunction;
        struct {
            nativeFunctionProc *proc;
        } nativeFunction;
    } u;
    struct FunctionDefinitionTag *next;
} FunctionDefinition;

typedef struct VariableTag {
    char *name;
    Value value;
    struct VariableTag *next;
} Variable;

typedef struct FrameTag {
    Variable *variable;
    FunctionDefinition *functionDefinition;
    struct FrameTag *parentFrame;
} Frame;

typedef enum {
    WdNormalStatementResult = 1,
    WdReturnStatementResult
} StatementResultType;

typedef struct {
    StatementResultType type;
    union {
        Value returnValue;
    } u;
} StatementResult;

#endif